package edu.towson.cosc.cosc455.cannon.compiler;

import edu.towson.cosc.cosc455.interfaces.SyntaxAnalyzer;

public class MySyntaxAnalyzer implements SyntaxAnalyzer {
	
	//setting terminals
	final String lolcodeBegin = "#HAI";				final String lolcodeEnd = "#KTHXBYE";
	final String commentBegin = "#OBTW";			final String commentEnd = "#TLDR";
	final String headBegin = "#MAEK HEAD";			final String paragraphBegin = "#MAEK PARAGRAF";
	final String listBegin = "#MAEK LIST";			final String oicEnd = "#OIC";
	final String titleBegin = "#GIMMEH TITLE";		final String boldBegin = "#GIMMEH BOLD";
	final String italicsBegin = "#GIMMEH ITALICS";	final String itemBegin = "#GIMMEH ITEM";
	final String audioBegin = "#GIMMEH SOUNDZ";		final String videoBegin = "#GIMMEH VIDZ";
	final String newline = "#GIMMEH NEWLINE";		final String mkayEnd = "#MKAY";
	final String variableBegin = "#I HAS A";		final String variableDefine = "#ITZ";
	final String variableCall = "#VISIBLE";

	@Override
	public void lolcode() {
		if (MyCompiler.token.equalsIgnoreCase(lolcodeBegin)) {
			MyCompiler.parseTree.add(MyCompiler.token);
			MyCompiler.Lexer.getNextToken();
			comment();
			define();
			head();
			body();
			if (MyCompiler.token.equalsIgnoreCase(lolcodeEnd)) {
				MyCompiler.parseTree.add(MyCompiler.token);
				MyCompiler.Lexer.getNextToken();
				if (MyCompiler.token != null) {
					System.err.println("Syntax error! There should be nothing after \"" + lolcodeEnd + "\".");
					System.exit(0);
				}
			}
			else {
				System.err.println("Syntax error! \"" + MyCompiler.token + "\" was found where \"" + lolcodeEnd + "\" was expected.");
				System.exit(0);
			}
		}
		else {
			System.err.println("Syntax error! \"" + MyCompiler.token + "\" was found where \"" + lolcodeBegin + "\" was expected.");
			System.exit(0);
		}
	}

	@Override
	public void comment() {
		if (MyCompiler.token.equalsIgnoreCase(commentBegin)) {
			MyCompiler.parseTree.add(MyCompiler.token);
			MyCompiler.Lexer.getNextToken();
			text();
			if (MyCompiler.token.equalsIgnoreCase(commentEnd)) {
				MyCompiler.parseTree.add(MyCompiler.token);
				MyCompiler.Lexer.getNextToken();
			}
			else {
				System.err.println("Syntax error! \"" + MyCompiler.token + "\" was found where \"" + commentEnd + "\" was expected.");
				System.exit(0);
			}
		}
	}

	@Override
	public void head() {
		if (MyCompiler.token.equalsIgnoreCase(headBegin)) {
			MyCompiler.parseTree.add(MyCompiler.token);
			MyCompiler.Lexer.getNextToken();
			title();
			if (MyCompiler.token.equalsIgnoreCase(oicEnd)) {
				MyCompiler.parseTree.add(MyCompiler.token);
				MyCompiler.Lexer.getNextToken();
			}
			else {
				System.err.println("Syntax error! \"" + MyCompiler.token + "\" was found where \"" + oicEnd + "\" was expected.");
				System.exit(0);
			}
		}
	}

	@Override
	public void title() {
		if (MyCompiler.token.equalsIgnoreCase(titleBegin)) {
			MyCompiler.parseTree.add(MyCompiler.token);
			MyCompiler.Lexer.getNextToken();
			text();
			if (MyCompiler.token.equalsIgnoreCase(mkayEnd)) {
				MyCompiler.parseTree.add(MyCompiler.token);
				MyCompiler.Lexer.getNextToken();
			}
			else {
				System.err.println("Syntax error! \"" + MyCompiler.token + "\" was found where \"" + mkayEnd + "\" was expected.");
				System.exit(0);
			}
		}
	}

	@Override
	public void paragraph() {
		if (MyCompiler.token.equalsIgnoreCase(paragraphBegin)) {
			MyCompiler.parseTree.add(MyCompiler.token);
			MyCompiler.Lexer.getNextToken();
			define();
			innerParagraph();
			if (MyCompiler.token.equalsIgnoreCase(oicEnd)) {
				MyCompiler.parseTree.add(MyCompiler.token);
				MyCompiler.Lexer.getNextToken();
			}
			else {
				System.err.println("Syntax error! \"" + MyCompiler.token + "\" was found where \"" + oicEnd + "\" was expected.");
				System.exit(0);
			}
		}
	}

	@Override
	public void bold() {
		if (MyCompiler.token.equalsIgnoreCase(boldBegin)) {
			MyCompiler.parseTree.add(MyCompiler.token);
			MyCompiler.Lexer.getNextToken();
			define();
			innerText();
			if (MyCompiler.token.equalsIgnoreCase(mkayEnd)) {
				MyCompiler.parseTree.add(MyCompiler.token);
				MyCompiler.Lexer.getNextToken();
			}
			else {
				System.err.println("Syntax error! \"" + MyCompiler.token + "\" was found where \"" + mkayEnd + "\" was expected.");
				System.exit(0);
			}
		}
	}

	@Override
	public void italics() {
		if (MyCompiler.token.equalsIgnoreCase(italicsBegin)) {
			MyCompiler.parseTree.add(MyCompiler.token);
			MyCompiler.Lexer.getNextToken();
			define();
			innerText();
			if (MyCompiler.token.equalsIgnoreCase(mkayEnd)) {
				MyCompiler.parseTree.add(MyCompiler.token);
				MyCompiler.Lexer.getNextToken();
			}
			else {
				System.err.println("Syntax error! \"" + MyCompiler.token + "\" was found where \"" + mkayEnd + "\" was expected.");
				System.exit(0);
			}
		}
	}

	@Override
	public void list() {
		if (MyCompiler.token.equalsIgnoreCase(listBegin)) {
			MyCompiler.parseTree.add(MyCompiler.token);
			MyCompiler.Lexer.getNextToken();
			if (MyCompiler.token.equalsIgnoreCase(itemBegin)) {
				MyCompiler.parseTree.add(MyCompiler.token);
				MyCompiler.Lexer.getNextToken();
				innerList();
				if (MyCompiler.token.equalsIgnoreCase(mkayEnd)) {
					MyCompiler.parseTree.add(MyCompiler.token);
					MyCompiler.Lexer.getNextToken();
					item();
					if (MyCompiler.token.equalsIgnoreCase(oicEnd)) {
						MyCompiler.parseTree.add(MyCompiler.token);
						MyCompiler.Lexer.getNextToken();
					}
					else {
						System.err.println("Syntax error! \"" + MyCompiler.token + "\" was found where \"" + oicEnd + "\" was expected.");
						System.exit(0);
					}
				}
				else {
					System.err.println("Syntax error! \"" + MyCompiler.token + "\" was found where \"" + mkayEnd + "\" was expected.");
					System.exit(0);
				}
			}
			else {
				System.err.println("Syntax error! \"" + MyCompiler.token + "\" was found where \"" + itemBegin + "\" was expected.");
				System.exit(0);
			}
		}
	}

	@Override
	public void item() {
		if (MyCompiler.token.equalsIgnoreCase(itemBegin)) {
			MyCompiler.parseTree.add(MyCompiler.token);
			MyCompiler.Lexer.getNextToken();
			innerList();
			if (MyCompiler.token.equalsIgnoreCase(mkayEnd)) {
				MyCompiler.parseTree.add(MyCompiler.token);
				MyCompiler.Lexer.getNextToken();
				item();
			}
			else {
				System.err.println("Syntax error! \"" + MyCompiler.token + "\" was found where \"" + mkayEnd + "\" was expected.");
				System.exit(0);
			}
		}
	}

	@Override
	public void audio() {
		if (MyCompiler.token.equalsIgnoreCase(audioBegin)) {
			MyCompiler.parseTree.add(MyCompiler.token);
			MyCompiler.Lexer.getNextToken();
			text();
			if (MyCompiler.token.equalsIgnoreCase(mkayEnd)) {
				MyCompiler.parseTree.add(MyCompiler.token);
				MyCompiler.Lexer.getNextToken();
			}
			else {
				System.err.println("Syntax error! \"" + MyCompiler.token + "\" was found where \"" + mkayEnd + "\" was expected.");
				System.exit(0);
			}
		}
	}

	@Override
	public void video() {
		if (MyCompiler.token.equalsIgnoreCase(videoBegin)) {
			MyCompiler.parseTree.add(MyCompiler.token);
			MyCompiler.Lexer.getNextToken();
			text();
			if (MyCompiler.token.equalsIgnoreCase(mkayEnd)) {
				MyCompiler.parseTree.add(MyCompiler.token);
				MyCompiler.Lexer.getNextToken();
			}
			else {
				System.err.println("Syntax error! \"" + MyCompiler.token + "\" was found where \"" + mkayEnd + "\" was expected.");
				System.exit(0);
			}
		}
	}

	@Override
	public void define() {
		if (MyCompiler.token.equalsIgnoreCase(variableBegin)) {
			MyCompiler.parseTree.add(MyCompiler.token);
			MyCompiler.Lexer.getNextToken();
			text();
			if (MyCompiler.token.equalsIgnoreCase(variableDefine)) {
				MyCompiler.parseTree.add(MyCompiler.token);
				MyCompiler.Lexer.getNextToken();
				text();
				if (MyCompiler.token.equalsIgnoreCase(mkayEnd)) {
					MyCompiler.parseTree.add(MyCompiler.token);
					MyCompiler.Lexer.getNextToken();
					define();
				}
				else {
					System.err.println("Syntax error! \"" + MyCompiler.token + "\" was found where \"" + mkayEnd + "\" was expected.");
					System.exit(0);
				}
			}
			else {
				System.err.println("Syntax error! \"" + MyCompiler.token + "\" was found where \"" + variableDefine + "\" was expected.");
				System.exit(0);
			}
		}
	}

	@Override
	public void use() {
		if (MyCompiler.token.equalsIgnoreCase(variableCall)) {
			MyCompiler.parseTree.add(MyCompiler.token);
			MyCompiler.Lexer.getNextToken();
			text();
			if (MyCompiler.token.equalsIgnoreCase(mkayEnd)) {
				MyCompiler.parseTree.add(MyCompiler.token);
				MyCompiler.Lexer.getNextToken();
			}
			else {
				System.err.println("Syntax error! \"" + MyCompiler.token + "\" was found where \"" + mkayEnd + "\" was expected.");
				System.exit(0);
			}
		}
	}
	
	public void body() {
		if (MyCompiler.token.equalsIgnoreCase(commentBegin)) {
			comment();
			body();
		}
		else if (MyCompiler.token.equalsIgnoreCase(paragraphBegin)) {
			paragraph();
			body();
		}
		else if (MyCompiler.token.equalsIgnoreCase(boldBegin)) {
			bold();
			body();
		}
		else if (MyCompiler.token.equalsIgnoreCase(italicsBegin)) {
			italics();
			body();
		}
		else if (MyCompiler.token.equalsIgnoreCase(listBegin)) {
			list();
			body();
		}
		else if (isInnerText()) {
			innerText();
			body();
		}
	}

	public void text() {
		MyCompiler.parseTree.add(MyCompiler.token);
		MyCompiler.Lexer.getNextToken();
	}
	
	public void innerParagraph() {
		if (isInnerText()) {
			innerText();
			innerParagraph();
		}
		else if (MyCompiler.token.equalsIgnoreCase(boldBegin)) {
			bold();
			innerParagraph();
		}
		else if (MyCompiler.token.equalsIgnoreCase(italicsBegin)) {
			italics();
			innerParagraph();
		}
		else if (MyCompiler.token.equalsIgnoreCase(listBegin)) {
			list();
			innerParagraph();
		}
		else if (MyCompiler.token.equalsIgnoreCase(newline)) {
			newline();
			innerParagraph();
		}
	}

	private void innerText() {
		if (MyCompiler.token.equalsIgnoreCase(variableCall)) {
			use();
			innerText();
		}
		else if (MyCompiler.token.equalsIgnoreCase(newline)) {
			newline();
			innerText();
		}
		else if (MyCompiler.token.equalsIgnoreCase(audioBegin)) {
			audio();
			innerText();
		}
		else if (MyCompiler.token.equalsIgnoreCase(videoBegin)) {
			video();
			innerText();
		}
		else if (MyCompiler.token.charAt(0) != '#') {
			text();
			innerText();
		}
	}
	
	private void innerList() {
		if (MyCompiler.token.equalsIgnoreCase(boldBegin)) {
			bold();
			innerList();
		}
		else if (MyCompiler.token.equalsIgnoreCase(italicsBegin)) {
			italics();
			innerList();
		}
		else if (MyCompiler.token.equalsIgnoreCase(listBegin)) {
			list();
			innerList();
		}
		else if (isInnerText()) {
			innerText();
			innerList();
		}
	}
	
	//if the current token is the start of anything innerText can be, it is assumed to be innerText
	private boolean isInnerText() {
		return 	MyCompiler.token.equalsIgnoreCase(variableCall) || MyCompiler.token.equalsIgnoreCase(newline) ||
				MyCompiler.token.equalsIgnoreCase(audioBegin) || MyCompiler.token.equalsIgnoreCase(videoBegin) ||
				MyCompiler.token.charAt(0) != '#' ;
	}
	
	private void newline() {
		if (MyCompiler.token.equalsIgnoreCase(newline)) {
			MyCompiler.parseTree.add(MyCompiler.token);
			MyCompiler.Lexer.getNextToken();
			newline();
		}
	}
}
